package com.sinsz.nacos.listener;

import com.alibaba.nacos.api.config.listener.Listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.StringReader;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * 配置监听
 *
 * @author chenjianbo
 * @date 2019-1-29
 */
public class NacosListener implements Listener {

    private static final Logger logger = LoggerFactory.getLogger(NacosListener.class);

    private static final ExecutorService executorService = new ThreadPoolExecutor(
            3,
            20,
            1500,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(),
            new NacosThreadFactory("NACOS")
    );

    /**
     * 判断合法类型
     * <p>
     *     目前对参数的解析仅支持常用部分基本数据类型及对应的封装类，另外支持String,Object类型
     * </p>
     * @param cls
     * @return
     */
    private boolean isLegalType(Class cls) {
        List<Class> classes = Arrays.asList(
                int.class, Integer.class,
                long.class, Long.class,
                float.class, Float.class,
                double.class, Double.class,
                boolean.class, Boolean.class,
                String.class,
                Object.class
        );
        return classes.contains(cls);
    }

    @Override
    public Executor getExecutor() {
        return executorService;
    }

    @Override
    public void receiveConfigInfo(String configInfo) {
        try {
            merge(configInfo);
        } catch (Exception e) {
            e.printStackTrace(System.out);
            logger.error("配置错误，请检查更正后重试");
        }
    }

    /**
     * 合并配置到缓存
     * @param content
     * @throws Exception
     */
    private void merge(String content) throws Exception {
        Properties p = new Properties();
        p.load(new StringReader(content));
        List<String> list = p.stringPropertyNames()
                .stream()
                .filter(str ->
                    str != null
                            && str.indexOf(".") > 0
                            && str.lastIndexOf(".") < str.length() - 1
                )
                .distinct()
                .collect(Collectors.toList());
        for (String str : list) {
            String className = str.substring(0, str.lastIndexOf("."));
            String fieldName = str.substring(str.lastIndexOf(".") + 1, str.length());
            Class clazz = Class.forName(className,false, Thread.currentThread().getContextClassLoader());
            Field field = clazz.getDeclaredField(fieldName);
            Object clazzObject = Cache.property.containsKey(className) ? Cache.property.get(className) : clazz.newInstance();
            if (isLegalType(field.getType())) {
                field.setAccessible(true);
                if (field.getType() == int.class || field.getType() == Integer.class) {
                    field.set(clazzObject, Integer.valueOf(p.get(str).toString()));
                } else if (field.getType() == long.class || field.getType() == Long.class) {
                    field.set(clazzObject, Long.valueOf(p.get(str).toString()));
                } else if (field.getType() == float.class || field.getType() == Float.class) {
                    field.set(clazzObject, Float.valueOf(p.get(str).toString()));
                } else if (field.getType() == double.class || field.getType() == Double.class) {
                    field.set(clazzObject, Double.valueOf(p.get(str).toString()));
                } else if (field.getType() == boolean.class || field.getType() == Boolean.class) {
                    field.set(clazzObject, Boolean.valueOf(p.get(str).toString()));
                } else {
                    field.set(clazzObject, p.get(str));
                }
            }
            Cache.property.put(className, clazzObject);
        }
        Cache.updateAutowired();
    }

}
